const Zip = require('./zip');
const {
  mapInfoResource,
  findApkIconPath,
  getBase64FromBuffer,
} = require('./utils');
const ManifestName = /^androidmanifest\.xml$/;
const ResourceName = /^resources\.arsc$/;

const ManifestXmlParser = require('./xml-parser/manifest');
const ResourceFinder = require('./resource-finder');

class ApkParser extends Zip {
  /**
   * parser for parsing .apk file
   * @param {String | File | Blob} file // file's path in Node, instance of File or Blob in Browser
   */
  constructor(file) {
    super(file);
    if (!(this instanceof ApkParser)) {
      return new ApkParser(file);
    }
  }
  parse() {
    return new Promise((resolve, reject) => {
      this.getEntries([ManifestName, ResourceName])
        .then((buffers) => {
          if (!buffers[ManifestName]) {
            throw new Error("AndroidManifest.xml can't be found.");
          }
          let apkInfo = this._parseManifest(buffers[ManifestName]);
          let resourceMap;
          if (!buffers[ResourceName]) {
            resolve(apkInfo);
          } else {
            // parse resourceMap
            resourceMap = this._parseResourceMap(buffers[ResourceName]);
            // update apkInfo with resourceMap
            apkInfo = mapInfoResource(apkInfo, resourceMap);

            // find icon path and parse icon
            const iconPath = findApkIconPath(apkInfo);
            if (iconPath) {
              this.getEntry(iconPath)
                .then((iconBuffer) => {
                  apkInfo.icon = iconBuffer
                    ? getBase64FromBuffer(iconBuffer)
                    : null;
                  resolve(apkInfo);
                })
                .catch((e) => {
                  apkInfo.icon = null;
                  resolve(apkInfo);
                  console.warn('[Warning] failed to parse icon: ', e);
                });
            } else {
              apkInfo.icon = null;
              resolve(apkInfo);
            }
          }
        })
        .catch((e) => {
          reject(e);
        });
    });
  }
  /**
   * Parse manifest
   * @param {Buffer} buffer // manifest file's buffer
   */
  _parseManifest(buffer) {
    try {
      const parser = new ManifestXmlParser(buffer, {
        ignore: [
          'application.activity',
          'application.service',
          'application.receiver',
          'application.provider',
          'permission-group',
        ],
      });
      return parser.parse();
    } catch (e) {
      throw new Error('Parse AndroidManifest.xml error: ' + (e.message || e));
    }
  }
  /**
   * Parse resourceMap
   * @param {Buffer} buffer // resourceMap file's buffer
   */
  _parseResourceMap(buffer) {
    try {
      return new ResourceFinder().processResourceTable(buffer);
    } catch (e) {
      throw new Error('Parser resources.arsc error: ' + e);
    }
  }
}

module.exports = ApkParser;
